MODULE TIMING_MOD

integer(4), parameter :: lb_proc_time = 1
integer(4), parameter :: ub_proc_time = 100
integer(4), parameter :: num_time_recs = ub_proc_time - lb_proc_time + 1

real(8) :: proc_time(lb_proc_time:ub_proc_time,1:2) = 0
real(8) :: proc_time_av(lb_proc_time:ub_proc_time,1:2) = 0
real(8) :: proc_time_max(lb_proc_time:ub_proc_time,1:2) = 0
real(8) :: proc_time_min(lb_proc_time:ub_proc_time,1:2) = 0
real(8) :: pr_time, pro_time

!data proc_time /200*0.d0/
!data proc_time_av /200*0.d0/

CONTAINS


SUBROUTINE PROC_TIME_AVER(ROOT, COMM3D, rank_MPI, nproc)

!use MPI

implicit none

include 'mpif.h'

! Input variables
integer(4), intent(in) :: ROOT
integer(4), intent(in) :: COMM3D
integer(4), intent(in) :: rank_MPI
integer(4), intent(in) :: nproc

! Local variables
integer(4) :: ierr_MPI

call MPI_REDUCE(proc_time(lb_proc_time,1), proc_time_av(lb_proc_time,1), &
 & num_time_recs, MPI_DOUBLE_PRECISION, MPI_SUM, ROOT, COMM3D, ierr_MPI)
call MPI_REDUCE(proc_time(lb_proc_time,2), proc_time_av(lb_proc_time,2), &
 & num_time_recs, MPI_DOUBLE_PRECISION, MPI_SUM, ROOT, COMM3D, ierr_MPI)

call MPI_REDUCE(proc_time(lb_proc_time,1), proc_time_max(lb_proc_time,1), &
 & num_time_recs, MPI_DOUBLE_PRECISION, MPI_MAX, ROOT, COMM3D, ierr_MPI)
call MPI_REDUCE(proc_time(lb_proc_time,2), proc_time_max(lb_proc_time,2), &
 & num_time_recs, MPI_DOUBLE_PRECISION, MPI_MAX, ROOT, COMM3D, ierr_MPI)

call MPI_REDUCE(proc_time(lb_proc_time,1), proc_time_min(lb_proc_time,1), &
 & num_time_recs, MPI_DOUBLE_PRECISION, MPI_MIN, ROOT, COMM3D, ierr_MPI)
call MPI_REDUCE(proc_time(lb_proc_time,2), proc_time_min(lb_proc_time,2), &
 & num_time_recs, MPI_DOUBLE_PRECISION, MPI_MIN, ROOT, COMM3D, ierr_MPI)

if (rank_MPI == ROOT) then
  proc_time_av = proc_time_av/real(nproc)
endif

END SUBROUTINE PROC_TIME_AVER


SUBROUTINE PROC_TIME_OUT(coords,nprocs,path)

implicit none

! Input variables
integer(4), intent(in) :: coords(1:3)
integer(4), intent(in) :: nprocs

character(len=*), intent(in) :: path

! Local variables

integer(4), parameter :: nunit = 777
integer(4) :: i, j ! Loop index

character(len=80) :: path1
character(len=80) :: format_char
character(len=3) :: c1, c2, c3, c4
character(len=10) :: file_position
 

call CHECK_UNIT0(nunit)

path1 = adjustl(path)
write (c1,'(i3.3)') coords(1)
write (c2,'(i3.3)') coords(2)
write (c3,'(i3.3)') coords(3)
write (c4,'(i3.3)') nprocs
path1 = path1(1:len_trim(path1))//c1//'.'//c2//'.'//c3//'.'//c4
! print*, 'filename = ', path1

file_position = 'append'
open (unit=nunit, file=path1, status='unknown', position=file_position)

write(nunit,*) '    Code segment N  ', 'Comp(1) or exch(2)  ', 'Mean     ', 'Max      ', 'Min'
format_char = '(2i20,3f20.10)'
do j = 1, 2
  do i = lb_proc_time, ub_proc_time
    if (proc_time_av(i,j)>0) then
      write(nunit,format_char) &
      & i, j, proc_time_av(i,j), proc_time_min(i,j), proc_time_max(i,j) !Output of process-averaged time characteristics
    endif
  enddo
enddo

! proc_time_av(1,1) - the total time (computations plus exchanges)
write(nunit,*) 'Total time of time integration loop = ', proc_time_av(1,1) ! - sum(proc_time_av(:,2))
write(nunit,*) 'MPI-exchanges time = ', sum(proc_time_av(:,2))

close(nunit)

END SUBROUTINE PROC_TIME_OUT

END MODULE TIMING_MOD
